﻿using System;
using System.Collections.Generic;
using System.Text;

namespace PLCTools.Driver
{
    public class SieDriver : PLCDriver
    {
        //192.168.0.1;200/102;0;0
        //192.168.0.1;300/102;0;2
        //192.168.0.1;1200/102;0;0
        private libnodave.daveInterface di;
        private libnodave.daveOSserialType fds;
        private libnodave.daveConnection dc;

        public override string ToString()
        {
            return "Siemens";
        }

        public override bool Connect(string ip, string param)
        {
            bool isS7_200 = false;
            lock (this)
            {
                if (IsConnected)
                {
                    return true;
                }
                try
                {
                    if (param.StartsWith("200/"))
                    {
                        param = param.Replace("200/", "");
                        isS7_200 = true;
                    }
                    IsConnected = false;
                    if (param == "")
                    {
                        param = "102";
                    }
                    string[] ary = param.Split(new char[] { ';' });
                    if (ary.Length == 1)
                    {
                        if (isS7_200)
                        {
                            ary = new string[] { ary[0], "0", "0" };
                        }
                        else
                        {
                            ary = new string[] { ary[0], "0", "2" };
                        }
                    }
                    if (ary.Length == 2)
                    {
                        if (isS7_200)
                        {
                            ary = new string[] { ary[0], ary[1], "0" };
                        }
                        else
                        {
                            ary = new string[] { ary[0], ary[1], "2" };
                        }
                    }
                    if ((fds.rfd = fds.wfd = libnodave.openSocket(Convert.ToInt32(ary[0]), ip)) <= 0)
                    {
                        throw new Exception();
                    }
                    if (isS7_200)
                    {
                        di = new libnodave.daveInterface(fds, "S7200", libnodave.daveProtoMPI/*libnodave.daveProtoPPI*/, libnodave.daveProtoISOTCP243, libnodave.daveSpeed93k);
                    }
                    else
                    {
                        di = new libnodave.daveInterface(fds, "S7300", libnodave.daveProtoMPI, libnodave.daveProtoISOTCP, libnodave.daveSpeed93k);
                    }
                    di.setTimeout(10000);
                    if (isS7_200)
                    {
                        dc = new libnodave.daveConnection(di, 0, Convert.ToInt32(ary[1]), Convert.ToInt32(ary[2]));
                    }
                    else
                    {
                        dc = new libnodave.daveConnection(di, 0, Convert.ToInt32(ary[1]), Convert.ToInt32(ary[2]));
                    }
                    if (0 != dc.connectPLC())
                    {
                        libnodave.closeSocket(fds.rfd);
                        throw new Exception();
                    }
                    IsConnected = true;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                return IsConnected;
            }
        }

        public override void Disconnect()
        {
            lock (this)
            {
                try
                {
                    IsConnected = false;
                    if (dc != null)
                    {
                        dc.disconnectPLC();
                    }
                    libnodave.closeSocket(fds.rfd);
                }
                catch
                {
                }
            }
        }

        public override bool ReadBytes(object addr, object[] data, DataType type, out byte[] buf)
        {
            buf = null;
            if (!IsConnected)
            {
                return false;
            }
            try
            {
                int len = GetLenFromDataType(type);
                buf = new byte[len * data.Length];
                int pos = 0;
                string[] address = addr.ToString().Split(new char[] { '.' });
                if (address.Length > 1)
                {
                    pos = Convert.ToInt32(address[1]);
                }
                if (type == DataType.SIE_BOOL)
                {
                    pos = pos * 8;
                    if (address.Length > 2)
                    {
                        pos += Convert.ToInt32(address[2]);
                    }
                    bool val;
                    for (int i = 0; i < data.Length; i++)
                    {
                        ReadDBBit(Convert.ToInt32(address[0]), pos + i, out val);
                        data[i] = val;
                        buf[i] = Convert.ToByte(val);
                    }
                }
                else
                {
                    ReadDBBytes(Convert.ToInt32(address[0]), pos, buf);
                    byte[] temp;
                    for (int i = 0; i < data.Length; i++)
                    {
                        temp = new byte[len];
                        Array.Copy(buf, i * len, temp, 0, temp.Length);
                        data[i] = GetObjectFromBytes(type, temp);
                    }
                }
                return true;
            }
            catch
            {
            }
            return false;
        }

        public override bool WriteBytes(object addr, object[] data, DataType type)
        {
            if (!IsConnected)
            {
                return false;
            }

            try
            {
                int len = GetLenFromDataType(type);
                byte[] buf = new byte[len * data.Length];
                byte[] temp;
                for (int i = 0; i < data.Length; i++)
                {
                    temp = GetBytesFromDataType(type, data[i]);
                    Array.Copy(temp, 0, buf, i * len, temp.Length);
                }
                int pos = 0;
                string[] address = addr.ToString().Split(new char[] { '.' });
                if (address.Length > 1)
                {
                    pos = Convert.ToInt32(address[1]);
                }
                if (type == DataType.SIE_BOOL)
                {
                    pos = pos * 8;
                    if (address.Length > 2)
                    {
                        pos += Convert.ToInt32(address[2]);
                    }
                    for (int i = 0; i < data.Length; i++)
                    {
                        WriteDBBit(Convert.ToInt32(address[0]), pos + i, Convert.ToBoolean(data[i]));
                    }
                }
                else
                {
                    WriteDBBytes(Convert.ToInt32(address[0]), pos, buf.Length, buf);
                }
                return true;
            }
            catch
            {
            }
            return false;
        }

        protected void ReadDBBytes(int DBNumber, int start, byte[] buf)
        {
            lock (this)
            {
                int rs = dc.readManyBytes(libnodave.daveDB, DBNumber, start, buf.Length, buf);
                if (rs == -1025)
                {
                    Disconnect();
                }
                if (rs != 0)
                {
                    throw new Exception("Read error");
                }
            }
        }

        protected void WriteDBBytes(int DBNumber, int start, int len, byte[] buf)
        {
            lock (this)
            {
                int rs = dc.writeManyBytes(libnodave.daveDB, DBNumber, start, len, buf);
                if (rs != 0)
                {
                    throw new Exception("Write error");
                }
            }
        }

        protected void ReadDBBit(int DBNumber, int pos, out bool val)
        {
            lock (this)
            {
                val = false;
                byte[] buf = new byte[1];
                int rs = 0;
                rs = dc.readBits(libnodave.daveDB, DBNumber, pos, 1, buf);
                val = (1 == buf[0]);
                if (rs == -1025)
                {
                    Disconnect();
                }
                if (rs != 0)
                {
                    throw new Exception("Read error");
                }
            }
        }

        protected void WriteDBBit(int DBNumber, int pos, bool val)
        {
            lock (this)
            {
                byte[] buf = new byte[] { (byte)(val ? 1 : 0) };
                int rs = 0;
                rs = dc.writeBits(libnodave.daveDB, DBNumber, pos, 1, buf);
                if (rs != 0)
                {
                    throw new Exception("Write error");
                }
            }
        }

        public override bool ReadBytesPLCDB(int DBNumber, int start, byte[] buf)
        {
            if (!IsConnected)
            {
                return false;
            }
            lock (this)
            {
                int rs = dc.readManyBytes(libnodave.daveDB, DBNumber, start, buf.Length, buf);
                if (rs == -1025)
                {
                    Disconnect();
                }
                if (rs != 0)
                {
                    return false;
                    //throw new Exception("Read error");
                }
                return true;
            }
        }

        public override bool WriteBytesPLCDB(int DBNumber, int start, byte[] buf)
        {
            if (!IsConnected)
            {
                return false;
            }
            lock (this)
            {
                int rs = dc.writeManyBytes(libnodave.daveDB, DBNumber, start, buf.Length, buf);
                if (rs != 0)
                {
                    return false;
                    //throw new Exception("Write error");
                }
                return true;
            }
        }

        public override bool WriteBitPLCDB(int DBNumber, int pos, bool val)
        {
            if (!IsConnected)
            {
                return false;
            }
            lock (this)
            {
                byte[] buf = new byte[] { (byte)(val ? 1 : 0) };
                int rs = 0;
                rs = dc.writeBits(libnodave.daveDB, DBNumber, pos, 1, buf);
                if (rs != 0)
                {
                    return false;
                    //throw new Exception("Write error");
                }
                return true;
            }
        }
    }
}
